#!/usr/bin/env python3
from __future__ import annotations

__package__ = __package__ or "tests.analyses.cfg"  # pylint:disable=redefined-builtin

import logging
import os
import unittest
from typing import TYPE_CHECKING

import pyvex

import angr
from angr.knowledge_plugins.cfg import IndirectJumpType
from angr.analyses.cfg import CFGFast
from angr.analyses.cfg.indirect_jump_resolvers import JumpTableResolver

if TYPE_CHECKING:
    from angr.knowledge_plugins.cfg import IndirectJump

from tests.common import bin_location


test_location = os.path.join(bin_location, "tests")
l = logging.getLogger("angr.tests.test_jumptables")


class J:
    """
    Simple jumptable wrapper for comparison.
    """

    def __init__(self, baddr, taddr, ents):
        self.block_addr = baddr
        self.table_addr = taddr
        self.entries = ents

    def __hash__(self):
        return hash((self.block_addr, self.table_addr, len(self.entries)))


# pylint:disable=line-too-long,no-self-use
class TestJumpTableResolver(unittest.TestCase):
    """
    Test cases for JumpTableResolver
    """

    @staticmethod
    def _compare(jump_tables, groundtruth):
        for j in groundtruth:
            assert j.block_addr in jump_tables, f"Jump table @ block {j.block_addr:#x} is not found in CFG."
            jumptable_addr = jump_tables[j.block_addr].jumptable_addr
            assert j.table_addr == jumptable_addr, "Mismatch jump table addresses (expecting {}, got {}).".format(
                (f"{j.table_addr:#x}") if j.table_addr is not None else "None",
                (f"{jumptable_addr:#x}") if jumptable_addr is not None else "None",
            )
            expected = set(j.entries)
            recovered = set(jump_tables[j.block_addr].jumptable_entries)

            if expected != recovered:
                missing = expected - recovered
                l.error(
                    "Expected table %#x referenced from %#x to have %d entries, it has %d:",
                    j.table_addr,
                    j.block_addr,
                    len(expected),
                    len(recovered),
                )
                if len(missing):
                    l.error("- Missing (%d): %s", len(missing), ", ".join([hex(a) for a in missing]))
                extra = recovered - expected
                if extra:
                    l.error("- Extra (%d): %s", len(extra), ", ".join([hex(a) for a in extra]))

            assert j.entries == jump_tables[j.block_addr].jumptable_entries

    def test_amd64_dir_gcc_O0(self):
        p = angr.Project(os.path.join(test_location, "x86_64", "dir_gcc_-O0"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        all_jumptables = {
            J(
                0x40404C,
                0x41B0A0,
                [
                    0x404741,
                    0x404737,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4043EF,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x404280,
                    0x40429D,
                    0x4042B6,
                    0x4042C5,
                    0x4047AD,
                    0x4042D1,
                    0x4042E0,
                    0x4042EC,
                    0x40430A,
                    0x4047AD,
                    0x4047AD,
                    0x40431E,
                    0x4047AD,
                    0x40432D,
                    0x4047AD,
                    0x4047AD,
                    0x404341,
                    0x404355,
                    0x404361,
                    0x404377,
                    0x4043C3,
                    0x4047AD,
                    0x4047AD,
                    0x4043D9,
                    0x4047AD,
                    0x40472B,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x404058,
                    0x404067,
                    0x40407B,
                    0x40408A,
                    0x4047AD,
                    0x404096,
                    0x4040FD,
                    0x404113,
                    0x404147,
                    0x4047AD,
                    0x404153,
                    0x40415F,
                    0x40416E,
                    0x40417D,
                    0x404193,
                    0x4041A9,
                    0x4041B8,
                    0x4041C4,
                    0x4041D0,
                    0x4041DC,
                    0x4041F2,
                    0x404201,
                    0x404217,
                    0x404271,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x4047AD,
                    0x40440C,
                    0x40468C,
                    0x404543,
                    0x4042FB,
                    0x4040EE,
                    0x4044E6,
                    0x404526,
                    0x40449A,
                    0x404418,
                    0x4045EA,
                    0x40462A,
                    0x404680,
                    0x4046F7,
                    0x404453,
                    0x4044A6,
                    0x404670,
                ],
            ),
            J(0x404D53, 0x41B938, [0x404D60, 0x404DE7, 0x404EA3, 0x404F00, 0x404FA5]),
            J(
                0x404DF6,
                0x41B960,
                [
                    0x404E61,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E02,
                    0x404E02,
                    0x404E02,
                    0x404E02,
                    0x404E02,
                    0x404E02,
                    0x404E02,
                    0x404E02,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E55,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E18,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E5B,
                    0x404E6A,
                    0x404E25,
                    0x404E2B,
                    0x404E6A,
                    0x404E6A,
                    0x404E31,
                    0x404E37,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E3D,
                    0x404E6A,
                    0x404E6A,
                    0x404E6A,
                    0x404E43,
                    0x404E6A,
                    0x404E49,
                    0x404E6A,
                    0x404E4F,
                    0x404E6A,
                    0x404E18,
                ],
            ),
            J(
                0x404F12,
                0x41BD28,
                [
                    0x404F1E,
                    0x404F1E,
                    0x404F1E,
                    0x404F1E,
                    0x404F1E,
                    0x404F1E,
                    0x404F1E,
                    0x404F1E,
                    0x404F1E,
                    0x404F1E,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F62,
                    0x404F62,
                    0x404F62,
                    0x404F62,
                    0x404F62,
                    0x404F62,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F84,
                    0x404F40,
                    0x404F40,
                    0x404F40,
                    0x404F40,
                    0x404F40,
                    0x404F40,
                ],
            ),
            J(0x4051B0, 0x41BF58, [0x405412, 0x4051BD, 0x40528B, 0x4052C0, 0x4053B5, 0x405412, 0x40541D]),
            J(
                0x405B34,
                0x41C088,
                [
                    0x405B9F,
                    0x405B64,
                    0x405B4C,
                    0x405B9F,
                    0x405B58,
                    0x405B9F,
                    0x405B40,
                    0x405B9F,
                    0x405B7C,
                    0x405B9F,
                    0x405B70,
                    0x405B9F,
                    0x405B88,
                    0x405B9F,
                    0x405B94,
                ],
            ),
            J(0x408899, 0x41C380, [0x408942, 0x4088A5, 0x4088F2, 0x408917, 0x408936]),
            J(
                0x410B5B,
                0x41E410,
                [
                    0x410CC9,
                    0x410C72,
                    0x410C85,
                    0x410C6E,
                    0x410C76,
                    0x410B79,
                    0x410B6B,
                    0x410BBA,
                    0x410BC7,
                    0x410BC7,
                    0x410BC7,
                ],
            ),
            J(
                0x410DA4,
                0x41E468,
                [
                    0x410DB0,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x41103C,
                    0x411042,
                    0x41105A,
                    0x41104E,
                    0x411060,
                    0x411048,
                    0x411054,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411195,
                    0x411102,
                    0x411102,
                    0x411102,
                    0x4110F7,
                    0x411102,
                    0x41155C,
                    0x411102,
                    0x41111E,
                    0x411102,
                    0x411102,
                    0x411102,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x411102,
                    0x411102,
                    0x411102,
                    0x411102,
                    0x410EF9,
                    0x411195,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x411102,
                    0x411066,
                    0x41155C,
                    0x411102,
                    0x41155C,
                    0x411102,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x41155C,
                    0x4110C5,
                    0x411102,
                    0x4110C5,
                    0x4110F7,
                ],
            ),
            J(
                0x410F84,
                0x41E860,
                [
                    0x410F90,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x410F90,
                    0x410F90,
                    0x410F90,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x410F90,
                    0x41102D,
                    0x410F90,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x41102D,
                    0x410F90,
                    0x410F90,
                    0x410F90,
                ],
            ),
            J(
                0x411300,
                0x41E950,
                [
                    0x4117B2,
                    0x4117B2,
                    0x41130C,
                    0x4117B2,
                    0x41130C,
                    0x4117B2,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x41130C,
                    0x4117B2,
                ],
            ),
            J(
                0x412AAE,
                0x41EA88,
                [
                    0x414B93,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x412ABE,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414905,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x412C2F,
                    0x412C85,
                    0x413105,
                    0x4131D1,
                    0x414BE3,
                    0x413BB4,
                    0x414295,
                    0x413BD1,
                    0x413BFD,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x413CBE,
                    0x413D2F,
                    0x414BE3,
                    0x413ED8,
                    0x414BE3,
                    0x413F09,
                    0x413F19,
                    0x4140B6,
                    0x41423E,
                    0x414295,
                    0x4145B5,
                    0x4140A4,
                    0x414660,
                    0x414749,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x414BE3,
                    0x412C02,
                    0x412C5C,
                    0x412CB2,
                    0x4131EE,
                    0x413217,
                    0x414BE3,
                    0x414295,
                    0x412C5C,
                    0x414BE3,
                    0x413C79,
                    0x413C25,
                    0x413C51,
                    0x413CEA,
                    0x413DAA,
                    0x414BE3,
                    0x413EE9,
                    0x414BE3,
                    0x412E7D,
                    0x413F44,
                    0x4140C6,
                    0x4141F4,
                    0x414BE3,
                    0x414634,
                    0x4131BF,
                    0x4146B6,
                    0x41495E,
                ],
            ),
            J(
                0x415060,
                0x41F0D8,
                [0x415073, 0x415078, 0x4150A8, 0x4150E3, 0x41512C, 0x415183, 0x4151EF, 0x415269, 0x4152F9, 0x415397],
            ),
            J(
                0x415FAA,
                0x41F268,
                [
                    0x415FCF,
                    0x4160EE,
                    0x4160EE,
                    0x415FF4,
                    0x4160EE,
                    0x416012,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x416030,
                    0x4160EE,
                    0x41604E,
                    0x4160EE,
                    0x4160EE,
                    0x41606C,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x416087,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x4160B8,
                    0x4160D3,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x415FB6,
                    0x415FE8,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x416012,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x416030,
                    0x4160EE,
                    0x41604E,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x4160EE,
                    0x416087,
                    0x4160EE,
                    0x4160EE,
                    0x4160A2,
                ],
            ),
            J(
                0x416586,
                0x41F4C8,
                [
                    0x4165AB,
                    0x4166CA,
                    0x4166CA,
                    0x4165D0,
                    0x4166CA,
                    0x4165EE,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x41660C,
                    0x4166CA,
                    0x41662A,
                    0x4166CA,
                    0x4166CA,
                    0x416648,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x416663,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x416694,
                    0x4166AF,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x416592,
                    0x4165C4,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x4165EE,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x41660C,
                    0x4166CA,
                    0x41662A,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x4166CA,
                    0x416663,
                    0x4166CA,
                    0x4166CA,
                    0x41667E,
                ],
            ),
            J(
                0x4177EC,
                0x41F6B0,
                [
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177FF,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                    0x4177F8,
                ],
            ),
        }

        self._compare(cfg.jump_tables, all_jumptables)

    def test_amd64_chmod_gcc_O1(self):
        p = angr.Project(os.path.join(test_location, "x86_64", "chmod_gcc_-O1"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        all_jumptables = {
            J(
                0x402322,
                0x4095A0,
                [
                    0x40246D,
                    0x4024BF,
                    0x4023D9,
                    0x4024BF,
                    0x40288B,
                    0x4023A5,
                    0x4024BF,
                    0x4024BF,
                    0x40232C,
                    0x4024BF,
                    0x4024BF,
                    0x402422,
                ],
            ),
            J(
                0x402FC1,
                0x409778,
                [
                    0x402FF2,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FFD,
                    0x402FCB,
                    0x402FE0,
                    0x402FE9,
                    0x402FFD,
                    0x402FFD,
                    0x402FD4,
                    0x402FDA,
                ],
            ),
            J(
                0x40360A,
                0x409920,
                [0x403614, 0x403F96, 0x403723, 0x40363C, 0x403F66, 0x403769, 0x40367D, 0x40367D, 0x40367D],
            ),
            J(
                0x4038D0,
                0x409968,
                [
                    0x4038EF,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403A91,
                    0x4038E5,
                    0x403A56,
                    0x403A76,
                    0x403A5D,
                    0x403A4F,
                    0x4038DB,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403B48,
                    0x403AD2,
                    0x403AD2,
                    0x403AD2,
                    0x403AC9,
                    0x403AD2,
                    0x403DF3,
                    0x403AD2,
                    0x403AF0,
                    0x403AD2,
                    0x403AD2,
                    0x403AD2,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403AD2,
                    0x403AD2,
                    0x403AD2,
                    0x403AD2,
                    0x40397C,
                    0x403B48,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403AD2,
                    0x403A64,
                    0x403DF3,
                    0x403AD2,
                    0x403DF3,
                    0x403AD2,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403AA4,
                    0x403AD2,
                    0x403AA4,
                    0x403AC9,
                ],
            ),
            J(
                0x4039DC,
                0x409D60,
                [
                    0x4039E6,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x4039E6,
                    0x4039E6,
                    0x4039E6,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x4039E6,
                    0x403DF3,
                    0x4039E6,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x403DF3,
                    0x4039E6,
                    0x4039E6,
                    0x4039E6,
                ],
            ),
            J(
                0x403C83,
                0x409E50,
                [
                    0x403F0D,
                    0x403F0D,
                    0x403C8D,
                    0x403F0D,
                    0x403C8D,
                    0x403F0D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403C8D,
                    0x403F0D,
                ],
            ),
            J(
                0x4048CA,
                0x40A250,
                [0x4048D2, 0x4048D7, 0x40490B, 0x404946, 0x404988, 0x4049D8, 0x404A2A, 0x404A8C, 0x404AF7, 0x404B73],
            ),
            J(
                0x406325,
                0x40A310,
                [
                    0x405FD8,
                    0x405F8C,
                    0x405FEB,
                    0x405FD8,
                    0x405F79,
                    0x405FD8,
                    0x406300,
                    0x405FD8,
                    0x405FB2,
                    0x405FD8,
                    0x405F9F,
                    0x405FD8,
                    0x405FC5,
                ],
            ),
            J(
                0x406399,
                0x40A378,
                [
                    0x405FDF,
                    0x405F93,
                    0x406374,
                    0x405FDF,
                    0x405F80,
                    0x405FDF,
                    0x406331,
                    0x405FDF,
                    0x405FB9,
                    0x405FDF,
                    0x405FA6,
                    0x405FDF,
                    0x405FCC,
                ],
            ),
        }

        self._compare(cfg.jump_tables, all_jumptables)

    def test_amd64_hostname_gcc_O2(self):
        p = angr.Project(os.path.join(test_location, "x86_64", "hostname"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        all_jumptables = {
            J(
                0x4025F5,
                0x40476C,
                [
                    0x4027AD,
                    0x402739,
                    0x402664,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402658,
                    0x402739,
                    0x402739,
                    0x40264D,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x40260F,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402607,
                    0x402642,
                    0x402739,
                    0x40263A,
                    0x402739,
                    0x4025FF,
                    0x402739,
                    0x4027AD,
                    0x402685,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x40267A,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x402739,
                    0x40266F,
                ],
            ),
            J(
                0x402D1F,
                0x404744,
                [0x402EE0, 0x402E10, 0x402E10, 0x402EF8, 0x402E10, 0x402E10, 0x402EC8, 0x402EB0, 0x402D38, 0x402D38],
            ),
        }

        self._compare(cfg.jump_tables, all_jumptables)

    def test_amd64_cfgswitches_gcc(self):
        p = angr.Project(os.path.join(test_location, "x86_64", "cfg_switches"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        all_jumptables = {
            J(
                0x4006E1,
                0x400A40,
                [
                    0x40075B,
                    0x4006EE,
                    0x4006FA,
                    0x4006EE,
                    0x40070B,
                    0x4006EE,
                    0x40071C,
                    0x4006EE,
                    0x40072D,
                    0x4006EE,
                    0x40073E,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40075B,
                    0x40074F,
                ],
            ),
            J(
                0x4005BC,
                0x4008C0,
                [
                    0x4006B0,
                    0x4006B0,
                    0x4005C9,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4005D8,
                    0x4006B0,
                    0x4005E7,
                    0x4006B0,
                    0x4005F6,
                    0x400605,
                    0x400614,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x400623,
                    0x4006B0,
                    0x400632,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x40063E,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x4006B0,
                    0x40064A,
                ],
            ),
            J(
                0x40053A,
                0x4007F8,
                [
                    0x40058D,
                    0x400547,
                    0x40058D,
                    0x400552,
                    0x40058D,
                    0x40055D,
                    0x40058D,
                    0x400568,
                    0x40058D,
                    0x400573,
                    0x40058D,
                    0x40058D,
                    0x400580,
                ],
            ),
            J(0x40065A, 0x4009F8, [0x4006A3, 0x400667, 0x400673, 0x40067F, 0x40068B, 0x400697]),
        }

        self._compare(cfg.jump_tables, all_jumptables)

    def test_i386_cfgswitches_gcc_O0(self):
        p = angr.Project(os.path.join(test_location, "i386", "cfg_switches_O0"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        all_jumptables = {
            J(
                0x8048432,
                0x8048770,
                [
                    0x8048487,
                    0x8048441,
                    0x8048487,
                    0x804844C,
                    0x8048487,
                    0x8048457,
                    0x8048487,
                    0x8048462,
                    0x8048487,
                    0x804846D,
                    0x8048487,
                    0x8048487,
                    0x804847A,
                ],
            ),
            J(
                0x80484B4,
                0x8048804,
                [
                    0x8048612,
                    0x8048612,
                    0x80484C3,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x80484D8,
                    0x8048612,
                    0x80484ED,
                    0x8048612,
                    0x8048502,
                    0x8048517,
                    0x804852C,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048541,
                    0x8048612,
                    0x8048556,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x804856B,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048612,
                    0x8048580,
                ],
            ),
            J(0x8048596, 0x80488A0, [0x80485FF, 0x80485A5, 0x80485B7, 0x80485C9, 0x80485DB, 0x80485ED]),
            J(
                0x8048654,
                0x80488CC,
                [
                    0x80486D5,
                    0x8048662,
                    0x8048671,
                    0x8048662,
                    0x8048682,
                    0x8048662,
                    0x8048693,
                    0x8048662,
                    0x80486A4,
                    0x8048662,
                    0x80486B5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486D5,
                    0x80486C6,
                ],
            ),
        }

        self._compare(cfg.jump_tables, all_jumptables)

    def test_i386_cfgswitches_gcc_O1(self):
        p = angr.Project(os.path.join(test_location, "i386", "cfg_switches_O1"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        all_jumptables = {
            J(
                0x804842F,
                0x8048700,
                [
                    0x804845A,
                    0x8048436,
                    0x804845A,
                    0x804843C,
                    0x804845A,
                    0x8048442,
                    0x804845A,
                    0x8048448,
                    0x804845A,
                    0x804844E,
                    0x804845A,
                    0x804845A,
                    0x8048454,
                ],
            ),
            J(
                0x804847E,
                0x8048734,
                [
                    0x80485D5,
                    0x80485D5,
                    0x8048485,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x804849F,
                    0x80485D5,
                    0x80484B1,
                    0x80485D5,
                    0x80484C3,
                    0x80484D5,
                    0x80484E7,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80484F9,
                    0x80485D5,
                    0x804850B,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x8048520,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x80485D5,
                    0x8048535,
                ],
            ),
            J(0x804854C, 0x80487D0, [0x80485C0, 0x8048557, 0x804856C, 0x8048581, 0x8048596, 0x80485AB]),
            J(
                0x8048610,
                0x80487E8,
                [
                    0x8048626,
                    0x8048626,
                    0x8048617,
                    0x8048626,
                    0x8048635,
                    0x8048626,
                    0x8048646,
                    0x8048626,
                    0x8048657,
                    0x8048626,
                    0x8048668,
                ],
            ),
        }

        self._compare(cfg.jump_tables, all_jumptables)

    def test_i386_cfgswitches_gcc_O2(self):
        p = angr.Project(os.path.join(test_location, "i386", "cfg_switches_O2"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        all_jumptables = {
            J(
                0x8048336,
                0x8048888,
                [
                    0x804834B,
                    0x804834B,
                    0x804833D,
                    0x804834B,
                    0x8048377,
                    0x804834B,
                    0x8048387,
                    0x804834B,
                    0x8048357,
                    0x804834B,
                    0x8048367,
                ],
            ),
            J(
                0x80484C9,
                0x80487A0,
                [
                    0x8048530,
                    0x80484E0,
                    0x8048530,
                    0x80484F0,
                    0x8048530,
                    0x8048500,
                    0x8048530,
                    0x8048510,
                    0x8048530,
                    0x8048520,
                    0x8048530,
                    0x8048530,
                    0x80484D0,
                ],
            ),
            J(
                0x804855E,
                0x80487D4,
                [
                    0x8048670,
                    0x8048670,
                    0x8048590,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x80485B0,
                    0x8048670,
                    0x80485C8,
                    0x8048670,
                    0x80485E0,
                    0x80485F8,
                    0x8048610,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048628,
                    0x8048670,
                    0x8048640,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048658,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048670,
                    0x8048568,
                ],
            ),
            J(0x8048583, 0x8048870, [0x8048700, 0x80486E8, 0x80486D0, 0x80486B8, 0x80486A0, 0x8048688]),
        }

        self._compare(cfg.jump_tables, all_jumptables)

    def test_kprca_00009(self):
        p = angr.Project(os.path.join(test_location, "cgc", "KPRCA_00009"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        all_jumptables = {
            J(
                0x804919A,
                0x804B890,
                [0x80491A4, 0x80494F9, 0x80494FE, 0x8049503, 0x8049508, 0x804950D, 0x8049512, 0x804951A],
            ),
            J(
                0x8049295,
                0x804B870,
                [0x804929F, 0x8049561, 0x8049566, 0x804956B, 0x8049570, 0x8049575, 0x804957A, 0x8049582],
            ),
            J(
                0x8048282,
                0x804B638,
                [
                    0x8048289,
                    0x8048CC9,
                    0x80483C3,
                    0x80485F6,
                    0x80483D5,
                    0x8048CC9,
                    0x80483F0,
                    0x8048CC9,
                    0x8048436,
                    0x80485AD,
                    0x8048448,
                    0x804845A,
                    0x8048487,
                    0x80484A2,
                    0x80484CA,
                    0x8048CC9,
                    0x8048520,
                    0x8048CC9,
                    0x804852F,
                    0x8048CC9,
                    0x8048541,
                    0x8048CC9,
                    0x804855C,
                    0x8048CC9,
                    0x80485A0,
                    0x80485CB,
                    0x80485ED,
                    0x8048CC9,
                    0x8048611,
                    0x8048CC9,
                    0x804864D,
                    0x8048CC9,
                    0x80486A3,
                    0x8048CC9,
                    0x80486C1,
                    0x8048CC9,
                    0x8048CC9,
                    0x8048CC9,
                    0x80486D4,
                    0x8048CC9,
                    0x80486ED,
                    0x8048714,
                    0x8048726,
                    0x8048CC9,
                    0x8048CC9,
                    0x8048CC9,
                    0x8048741,
                    0x8048CC9,
                    0x804876D,
                    0x8048CC9,
                    0x804878D,
                    0x804879D,
                    0x8048CC9,
                    0x8048CC9,
                    0x80487A4,
                    0x8048CC9,
                    0x80487BC,
                    0x80487E3,
                    0x80487FA,
                    0x8048817,
                    0x8048CC9,
                    0x8048CC9,
                    0x804882B,
                ],
            ),
            J(
                0x8049211,
                0x804B850,
                [0x804921B, 0x8049533, 0x8049538, 0x804953D, 0x8049542, 0x8049547, 0x804954C, 0x8049554],
            ),
            J(
                0x80492BD,
                0x804B830,
                [0x80492C7, 0x80495A1, 0x80495A6, 0x80495AB, 0x80495B0, 0x80495B5, 0x80495BA, 0x80495C2],
            ),
            J(0x8048CD8, 0x804B77C, [0x8048CDF, 0x8048CFD, 0x8048DEA, 0x8048E11, 0x8048E38]),
            J(0x8048D48, 0x804B800, [0x8048D52, 0x8048F12, 0x8048F17, 0x8048F1C]),
            J(
                0x8049EBC,
                0x804BA58,
                [
                    0x8049F0A,
                    0x8049F68,
                    0x8049EC3,
                    0x8049F68,
                    0x8049F68,
                    0x8049F18,
                    0x8049F68,
                    0x8049F68,
                    0x8049F68,
                    0x8049F68,
                    0x8049F1E,
                    0x8049F24,
                    0x8049F2A,
                ],
            ),
            J(0x8048D20, 0x804B820, [0x8048D2A, 0x8048EEE, 0x8048EF3, 0x8048EF8]),
            J(
                0x8049EEC,
                0x804B9FC,
                [
                    0x8049EF3,
                    0x8049F68,
                    0x8049F68,
                    0x8049F30,
                    0x8049F68,
                    0x8049F68,
                    0x8049F68,
                    0x8049F0A,
                    0x8049F36,
                    0x8049F3C,
                    0x8049F42,
                    0x8049F68,
                    0x8049F68,
                    0x8049F68,
                    0x8049F68,
                    0x8049F68,
                    0x8049F48,
                    0x8049F68,
                    0x8049F58,
                    0x8049F68,
                    0x8049F5E,
                    0x8049F68,
                    0x8049F64,
                ],
            ),
            J(0x8048D70, 0x804B810, [0x8048D7A, 0x8048FC9, 0x8048FD1, 0x8048FD9]),
            J(0x8048D9B, 0x804B7F0, [0x8048DA5, 0x8048FE1, 0x8048FE9, 0x8048FF1]),
            J(
                0x8048DD8,
                0x804B950,
                [0x8048DE2, 0x804913C, 0x8049141, 0x8049146, 0x804914B, 0x8049150, 0x8049155, 0x804915D],
            ),
            J(
                0x8049169,
                0x804B970,
                [0x8049173, 0x80491AC, 0x80491B1, 0x80491B6, 0x80491BB, 0x80491C0, 0x80491C5, 0x80491CD],
            ),
            J(
                0x80489DA,
                0x804B734,
                [
                    0x80489E1,
                    0x8048B46,
                    0x8048CC9,
                    0x8048CC9,
                    0x8048CC9,
                    0x8048CC9,
                    0x8048CC9,
                    0x8048CC9,
                    0x8048B5E,
                    0x8048B6D,
                ],
            ),
            J(
                0x8048E85,
                0x804B910,
                [0x8048E8F, 0x8049223, 0x8049228, 0x804922D, 0x8049232, 0x8049237, 0x804923C, 0x8049244],
            ),
            J(
                0x8048EDC,
                0x804B8F0,
                [0x8048EE6, 0x8049387, 0x804938C, 0x8049391, 0x8049396, 0x804939B, 0x80493A0, 0x80493A8],
            ),
            J(
                0x8048F81,
                0x804B8D0,
                [0x8048F8B, 0x804942B, 0x8049430, 0x8049435, 0x804943A, 0x804943F, 0x8049444, 0x804944C],
            ),
            J(0x8049327, 0x804B930, [0x8049331, 0x8049600, 0x8049605, 0x804960A]),
            J(
                0x804902B,
                0x804B8B0,
                [0x8049035, 0x8049482, 0x8049487, 0x804948C, 0x8049491, 0x8049496, 0x804949B, 0x80494A3],
            ),
            J(0x8049375, 0x804B940, [0x804937F, 0x8049627, 0x804962C, 0x8049631]),
            J(
                0x8048E49,
                0x804B790,
                [0x8048E53, 0x80490FC, 0x8049101, 0x8049106, 0x804910B, 0x8049110, 0x8049115, 0x804911D],
            ),
            J(
                0x8048E26,
                0x804B7B0,
                [0x8048E30, 0x804908F, 0x8049094, 0x8049099, 0x804909E, 0x80490A3, 0x80490A8, 0x80490B0],
            ),
            J(
                0x8048DFF,
                0x804B7D0,
                [0x8048E09, 0x804903D, 0x8049042, 0x8049047, 0x804904C, 0x8049051, 0x8049056, 0x804905E],
            ),
            J(
                0x8048473,
                0x804B75C,
                [0x804847F, 0x8048A11, 0x8048A16, 0x8048A1B, 0x8048A20, 0x8048A25, 0x8048A2A, 0x8048A32],
            ),
        }

        self._compare(cfg.jump_tables, all_jumptables)

    def test_armel_cfgswitches_gcc(self):
        p = angr.Project(os.path.join(test_location, "armel", "cfg_switches"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        all_jumptables = {
            J(
                0x10734,
                0x10748,
                [
                    0x107FC,
                    0x10808,
                    0x107FC,
                    0x10818,
                    0x107FC,
                    0x10828,
                    0x107FC,
                    0x10838,
                    0x107FC,
                    0x10848,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10864,
                    0x10858,
                ],
            ),
            J(
                0x10434,
                0x10458,
                [
                    0x10488,
                    0x104E8,
                    0x10498,
                    0x104E8,
                    0x104A8,
                    0x104E8,
                    0x104B8,
                    0x104E8,
                    0x104C8,
                    0x104E8,
                    0x104E8,
                    0x104D8,
                ],
            ),
            J(
                0x10524,
                0x10538,
                [
                    0x105CC,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x105D8,
                    0x106B4,
                    0x105E4,
                    0x106B4,
                    0x105F0,
                    0x105FC,
                    0x10608,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x10614,
                    0x106B4,
                    0x10620,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x1062C,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x106B4,
                    0x10638,
                ],
            ),
            J(0x10640, 0x10654, [0x10668, 0x10674, 0x10680, 0x1068C, 0x10698]),
        }

        self._compare(cfg.jump_tables, all_jumptables)

    def test_armel_lwip_tcpecho_bm(self):
        p = angr.Project(os.path.join(test_location, "armel", "lwip_tcpecho_bm.elf"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        all_jumptables = {
            J(
                0x14FB,
                0x14FE,
                [
                    0x1519,
                    0x1519,
                    0x152F,
                    0x1541,
                    0x1553,
                    0x159D,
                    0x1565,
                    0x156D,
                    0x1575,
                    0x159D,
                    0x159D,
                    0x157D,
                    0x1585,
                    0x158D,
                    0x1595,
                    0x159D,
                    0x159D,
                    0x159D,
                    0x15A1,
                    0x1513,
                ],
            ),
            J(0x2D45, 0x2D48, [0x2D8D, 0x2D4F, 0x2D91, 0x2D7F, 0x2D7F]),
            J(0x2E8D, 0x2E90, [0x2EB3, 0x2E97, 0x2EB7, 0x2EA7, 0x2EA7]),
            J(0x2E9F, 0x2EA2, [0x2F93, 0x2FC9, 0x2FC9, 0x2EBB]),
            J(0x4B63, 0x4B66, [0x4B91, 0x4C81, 0x4D53, 0x4D5B, 0x4DED, 0x4D53, 0x4E21, 0x4E5F]),
        }

        self._compare(cfg.jump_tables, all_jumptables)

    def test_s390x_cfgswitches(self):
        p = angr.Project(os.path.join(test_location, "s390x", "cfg_switches"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        all_jumptables = {
            J(
                0x400638,
                0x400C00,
                [0x40064E, 0x40065C, 0x400692, 0x40065C, 0x4006A4, 0x40065C, 0x40066E, 0x40065C, 0x400680],
            ),
            J(
                0x4007D4,
                0x400A50,
                [
                    0x4007EA,
                    0x4007CA,
                    0x4007F4,
                    0x4007CA,
                    0x4007FE,
                    0x4007CA,
                    0x400808,
                    0x4007CA,
                    0x400812,
                    0x4007CA,
                    0x4007CA,
                    0x40081C,
                ],
            ),
            J(
                0x400872,
                0x400AB0,
                [
                    0x4008AE,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x4008BE,
                    0x400854,
                    0x4008CE,
                    0x400854,
                    0x4008DE,
                    0x4008EE,
                    0x4008FE,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x40090E,
                    0x400854,
                    0x40091E,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x40092E,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400854,
                    0x400888,
                ],
            ),
            J(0x40093E, 0x400BD8, [0x400984, 0x400974, 0x400964, 0x400954, 0x400994]),
        }

        self._compare(cfg.jump_tables, all_jumptables)

    def test_arm_libsoap(self):
        # This is the ADDLS type of jump table (IndirectJumpType.JumpTable_AddressComputed) where no actual table is
        # used libsoap.so seems to be compiled from gSOAP, which is an open-source product

        p = angr.Project(os.path.join(test_location, "armel", "libsoap.so"), auto_load_libs=False)
        cfg = p.analyses.CFGFast(data_references=True)

        all_jumptabes = {
            J(
                0x411C8C,
                None,
                [
                    0x411C9C,
                    0x411CA0,
                    0x411CA4,
                    0x411CA8,
                    0x411CAC,
                    0x411CB0,
                    0x411CB4,
                    0x411CB8,
                    0x411CBC,
                    0x411CC0,
                    0x411CC4,
                    0x411CC8,
                    0x411CCC,
                    0x411CD0,
                    0x411CD4,
                    0x411CD8,
                    0x411CDC,
                    0x411CE0,
                    0x411CE4,
                    0x411CE8,
                    0x411CEC,
                    0x411CF0,
                    0x411CF4,
                    0x411CF8,
                    0x411CFC,
                    0x411D00,
                    0x411D04,
                    0x411D08,
                    0x411D0C,
                    0x411D10,
                    0x411D14,
                    0x411D18,
                    0x411D1C,
                    0x411D20,
                    0x411D24,
                    0x411D28,
                    0x411D2C,
                    0x411D30,
                    0x411D34,
                    0x411D38,
                    0x411D3C,
                    0x411D40,
                    0x411D44,
                    0x411D48,
                    0x411D4C,
                    0x411D50,
                    0x411D54,
                    0x411D58,
                    0x411D5C,
                    0x411D60,
                    0x411D64,
                    0x411D68,
                    0x411D6C,
                    0x411D70,
                ],
            ),
            J(
                0x411F54,
                None,
                [
                    0x411F64,
                    0x411F68,
                    0x411F6C,
                    0x411F70,
                    0x411F74,
                    0x411F78,
                    0x411F7C,
                    0x411F80,
                    0x411F84,
                    0x411F88,
                    0x411F8C,
                    0x411F90,
                    0x411F94,
                    0x411F98,
                    0x411F9C,
                    0x411FA0,
                    0x411FA4,
                    0x411FA8,
                    0x411FAC,
                    0x411FB0,
                    0x411FB4,
                    0x411FB8,
                    0x411FBC,
                    0x411FC0,
                    0x411FC4,
                    0x411FC8,
                    0x411FCC,
                    0x411FD0,
                    0x411FD4,
                    0x411FD8,
                    0x411FDC,
                    0x411FE0,
                    0x411FE4,
                    0x411FE8,
                    0x411FEC,
                    0x411FF0,
                    0x411FF4,
                    0x411FF8,
                    0x411FFC,
                    0x412000,
                    0x412004,
                    0x412008,
                    0x41200C,
                    0x412010,
                    0x412014,
                    0x412018,
                    0x41201C,
                    0x412020,
                    0x412024,
                    0x412028,
                    0x41202C,
                    0x412030,
                    0x412034,
                    0x412038,
                ],
            ),
            J(0x41B0B4, None, [0x41B0C4, 0x41B0C8, 0x41B0CC, 0x41B0D0, 0x41B0D4]),
            # 0x41d0e8 and 0x41d0fc are the same jump table - they appear twice because the CFG is not normalized
            # (the two blocks 0x41d0e8 and 0x41d0fc overlap and end at the same instruction)
            J(
                0x41D0E8,
                None,
                [
                    0x41D10C,
                    0x41D110,
                    0x41D114,
                    0x41D118,
                    0x41D11C,
                    0x41D120,
                    0x41D124,
                    0x41D128,
                    0x41D12C,
                    0x41D130,
                    0x41D134,
                    0x41D138,
                    0x41D13C,
                    0x41D140,
                    0x41D144,
                    0x41D148,
                    0x41D14C,
                    0x41D150,
                    0x41D154,
                    0x41D158,
                    0x41D15C,
                    0x41D160,
                    0x41D164,
                    0x41D168,
                    0x41D16C,
                    0x41D170,
                    0x41D174,
                    0x41D178,
                    0x41D17C,
                ],
            ),
            J(
                0x41D0FC,
                None,
                [
                    0x41D10C,
                    0x41D110,
                    0x41D114,
                    0x41D118,
                    0x41D11C,
                    0x41D120,
                    0x41D124,
                    0x41D128,
                    0x41D12C,
                    0x41D130,
                    0x41D134,
                    0x41D138,
                    0x41D13C,
                    0x41D140,
                    0x41D144,
                    0x41D148,
                    0x41D14C,
                    0x41D150,
                    0x41D154,
                    0x41D158,
                    0x41D15C,
                    0x41D160,
                    0x41D164,
                    0x41D168,
                    0x41D16C,
                    0x41D170,
                    0x41D174,
                    0x41D178,
                    0x41D17C,
                ],
            ),
            J(
                0x41D9D0,
                None,
                [
                    0x41D9E0,
                    0x41D9E4,
                    0x41D9E8,
                    0x41D9EC,
                    0x41D9F0,
                    0x41D9F4,
                    0x41D9F8,
                    0x41D9FC,
                    0x41DA00,
                    0x41DA04,
                    0x41DA08,
                    0x41DA0C,
                    0x41DA10,
                    0x41DA14,
                    0x41DA18,
                    0x41DA1C,
                    0x41DA20,
                    0x41DA24,
                    0x41DA28,
                    0x41DA2C,
                    0x41DA30,
                    0x41DA34,
                    0x41DA38,
                    0x41DA3C,
                    0x41DA40,
                    0x41DA44,
                    0x41DA48,
                    0x41DA4C,
                    0x41DA50,
                    0x41DA54,
                    0x41DA58,
                    0x41DA5C,
                    0x41DA60,
                    0x41DA64,
                    0x41DA68,
                    0x41DA6C,
                    0x41DA70,
                    0x41DA74,
                    0x41DA78,
                    0x41DA7C,
                    0x41DA80,
                    0x41DA84,
                    0x41DA88,
                    0x41DA8C,
                    0x41DA90,
                    0x41DA94,
                    0x41DA98,
                    0x41DA9C,
                    0x41DAA0,
                    0x41DAA4,
                    0x41DAA8,
                    0x41DAAC,
                    0x41DAB0,
                    0x41DAB4,
                ],
            ),
            J(
                0x41E070,
                None,
                [
                    0x41E080,
                    0x41E084,
                    0x41E088,
                    0x41E08C,
                    0x41E090,
                    0x41E094,
                    0x41E098,
                    0x41E09C,
                    0x41E0A0,
                    0x41E0A4,
                    0x41E0A8,
                    0x41E0AC,
                    0x41E0B0,
                    0x41E0B4,
                    0x41E0B8,
                    0x41E0BC,
                    0x41E0C0,
                    0x41E0C4,
                    0x41E0C8,
                    0x41E0CC,
                    0x41E0D0,
                    0x41E0D4,
                    0x41E0D8,
                    0x41E0DC,
                    0x41E0E0,
                    0x41E0E4,
                    0x41E0E8,
                    0x41E0EC,
                    0x41E0F0,
                    0x41E0F4,
                    0x41E0F8,
                    0x41E0FC,
                    0x41E100,
                    0x41E104,
                    0x41E108,
                    0x41E10C,
                    0x41E110,
                    0x41E114,
                    0x41E118,
                    0x41E11C,
                    0x41E120,
                    0x41E124,
                    0x41E128,
                    0x41E12C,
                    0x41E130,
                    0x41E134,
                    0x41E138,
                    0x41E13C,
                    0x41E140,
                    0x41E144,
                    0x41E148,
                    0x41E14C,
                    0x41E150,
                    0x41E154,
                    0x41E158,
                    0x41E15C,
                    0x41E160,
                    0x41E164,
                    0x41E168,
                    0x41E16C,
                    0x41E170,
                    0x41E174,
                    0x41E178,
                    0x41E17C,
                    0x41E180,
                    0x41E184,
                    0x41E188,
                    0x41E18C,
                    0x41E190,
                ],
            ),
        }

        self._compare(cfg.jump_tables, all_jumptabes)

        assert 0x41D0E8 in cfg.model.jump_tables
        # normalizing the CFG should remove 0x41d0e8
        cfg.normalize()
        assert 0x41D0E8 not in cfg.model.jump_tables

    #
    # The jump table should be occupied and marked as data
    #

    def test_jumptable_occupied_as_data(self):
        # GitHub issue #1671

        p = angr.Project(os.path.join(test_location, "i386", "windows", "printenv.exe"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()

        # it has a jump table at 0x402e4d with 10 entries
        assert 0x402E4D in cfg.indirect_jumps
        assert cfg.indirect_jumps[0x402E4D].jumptable is True
        assert cfg.indirect_jumps[0x402E4D].jumptable_addr == 0x402E54
        assert cfg.indirect_jumps[0x402E4D].jumptable_size == 4 * 10
        assert cfg.indirect_jumps[0x402E4D].jumptable_entry_size == 4

        # 40 bytes starting at 0x402e4d should be marked as "data"
        for addr in range(0x402E54, 0x402E54 + 40, 4):
            assert cfg._seg_list.occupied_by_sort(addr) == "pointer-array"

        # node 0x402e4d should have 10 successors
        assert len(cfg.model.get_any_node(0x402E4D).successors) == 10

    #
    # Some jump tables are in fact vtables
    #

    def test_vtable_amd64_libc_ubuntu_2004(self):
        p = angr.Project(
            os.path.join(test_location, "x86_64", "elf_with_static_libc_ubuntu_2004_stripped"), auto_load_libs=False
        )
        cfg = p.analyses.CFGFast()

        assert 0x46D710 in cfg.indirect_jumps
        ij: IndirectJump = cfg.indirect_jumps[0x46D710]
        assert ij.type == IndirectJumpType.Vtable
        assert len(ij.jumptable_entries) == 213

        # all non-zero entries in a vtable should be made functions
        for entry in ij.jumptable_entries:
            if entry != 0:
                assert entry in cfg.functions

    def test_mips_jumptable0(self):
        p = angr.Project(os.path.join(test_location, "mipsel", "jumptable_0"), auto_load_libs=False)
        cfg = p.analyses[CFGFast].prep()()

        assert 0x40D1A4 in cfg.model.jump_tables
        jumptable = cfg.model.jump_tables[0x40D1A4]
        assert len(jumptable.jumptable_entries) == 19
        assert jumptable.jumptable_entries == [
            0x40D1E0,
            0x40D278,
            0x40D200,
            0x40D278,
            0x40D278,
            0x40D278,
            0x40D278,
            0x40D278,
            0x40D278,
            0x40D278,
            0x40D1C8,
            0x40D278,
            0x40D278,
            0x40D278,
            0x40D278,
            0x40D250,
            0x40D270,
            0x40D278,
            0x40D1F8,
        ]

    def test_amd64_fmt0_with_constant_propagation_r12(self):
        p = angr.Project(os.path.join(test_location, "x86_64", "fmt_0"), auto_load_libs=False)
        cfg = p.analyses[CFGFast].prep()()

        assert 0x401ACC in cfg.model.jump_tables
        jumptable = cfg.model.jump_tables[0x401ACC]
        assert len(jumptable.jumptable_entries) == 21
        assert jumptable.jumptable_entries == [
            0x401B48,
            0x401D6A,
            0x401D6A,
            0x401D6A,
            0x401B30,
            0x401D6A,
            0x401D6A,
            0x401D6A,
            0x401D6A,
            0x401D6A,
            0x401D6A,
            0x401D6A,
            0x401D6A,
            0x401B18,
            0x401D6A,
            0x401D6A,
            0x401B08,
            0x401AF8,
            0x401AE8,
            0x401D6A,
            0x401AD8,
        ]

    def test_amd64_win_jumptable_with_secondary_redirections(self):
        p = angr.Project(os.path.join(test_location, "x86_64", "windows", "WinDivert.sys"), auto_load_libs=False)
        cfg = p.analyses[CFGFast].prep()()

        assert 0x17C5C in cfg.model.jump_tables
        assert len(cfg.model.jump_tables[0x17C5C].jumptable_entries) == 85
        assert cfg.model.jump_tables[0x17C5C].jumptable_entries == [
            0x17C7A,
            0x17C86,
            0x17C86,
            0x17D95,
            0x17D95,
            0x17C9E,
            0x17C9E,
            0x17C9E,
            0x17C9E,
            0x17C9E,
            0x17C9E,
            0x17E0E,
            0x17E0E,
            0x17E0E,
            0x17E0E,
            0x17E0E,
            0x17E0E,
            0x17E0E,
            0x17E0E,
            0x17E0E,
            0x17E0E,
            0x17E0E,
            0x17E0E,
            0x17E2D,
            0x17E2D,
            0x17E2D,
            0x17E2D,
            0x17E2D,
            0x17E2D,
            0x17E2D,
            0x17E43,
            0x17E43,
            0x17E43,
            0x17E43,
            0x17E6F,
            0x17E6F,
            0x17E6F,
            0x17E6F,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17EA2,
            0x17EA2,
            0x17EA2,
            0x17EA2,
            0x17EA2,
            0x17C9E,
            0x17C9E,
            0x17DD0,
            0x17DAF,
            0x17DAF,
            0x17DAF,
            0x17DAF,
            0x17DAF,
            0x17DF0,
            0x17DF0,
            0x17DFE,
            0x17DFE,
            0x17C7A,
            0x17D95,
            0x17D95,
            0x17D95,
            0x17E8C,
            0x17E8C,
            0x17E8C,
            0x17EA2,
            0x17EA2,
            0x17EA2,
            0x17D95,
            0x17C7A,
            0x17CAE,
            0x17CAE,
            0x17CAE,
        ]
        assert 0x18D89 in cfg.model.jump_tables
        assert len(cfg.model.jump_tables[0x18D89].jumptable_entries) == 84
        assert cfg.model.jump_tables[0x18D89].jumptable_entries == [
            0x18DA7,
            0x18DA7,
            0x18DA7,
            0x18EB6,
            0x18EB6,
            0x18DA7,
            0x18DA7,
            0x18DA7,
            0x18DA7,
            0x18DA7,
            0x18DA7,
            0x18E3C,
            0x18E46,
            0x18E5A,
            0x18E5A,
            0x18DA7,
            0x18DA7,
            0x18E50,
            0x18E46,
            0x18E46,
            0x18E5A,
            0x18E80,
            0x18E80,
            0x18E46,
            0x18E76,
            0x18E5A,
            0x18E46,
            0x18E46,
            0x18EA7,
            0x18EA7,
            0x18E46,
            0x18E46,
            0x18E5A,
            0x18EB6,
            0x18E46,
            0x18E46,
            0x18E5A,
            0x18EB6,
            0x18E5A,
            0x18E5A,
            0x18EB6,
            0x18EB6,
            0x18E3C,
            0x18DA7,
            0x18DA7,
            0x18DA7,
            0x18DA7,
            0x18DA7,
            0x18DA7,
            0x18E5A,
            0x18E5A,
            0x18E5A,
            0x18E5A,
            0x18E5A,
            0x18E5A,
            0x18E5A,
            0x18E5A,
            0x18E5A,
            0x18EB6,
            0x18EB6,
            0x18EB6,
            0x18EA7,
            0x18EA7,
            0x18E5A,
            0x18E5A,
            0x18E46,
            0x18EB1,
            0x18EB1,
            0x18DB1,
            0x18DBE,
            0x18DD6,
            0x18E46,
            0x18E5A,
            0x18EB6,
            0x18E46,
            0x18E5A,
            0x18EB6,
            0x18E46,
            0x18E5A,
            0x18EB6,
            0x18E64,
            0x18E92,
            0x18E46,
            0x18E5A,
        ]

    def test_amd64_rust_jumptable_single_block_no_overbound_check(self):
        p = angr.Project(
            os.path.join(test_location, "x86_64", "1cbbf108f44c8f4babde546d26425ca5340dccf878d306b90eb0fbec2f83ab51"),
            auto_load_libs=False,
        )
        cfg = p.analyses[CFGFast].prep()()

        assert 0x40BD1B in cfg.model.jump_tables
        assert len(cfg.model.jump_tables[0x40BD1B].jumptable_entries) == 4
        assert cfg.model.jump_tables[0x40BD1B].jumptable_entries == [0x40BD38, 0x40C5D1, 0x40C59E, 0x40C5AE]

    def test_arm_thumb_jumptable_multi_variable_ranges(self):
        # Correctly resolving this indirect jump requires Balancer (in claripy) to handle the range of the addition of
        # two symbolic variables.
        proj = angr.Project(os.path.join(test_location, "armhf", "AP_GPS_NMEA.cpp.0.o"), auto_load_libs=False)
        cfg = proj.analyses[CFGFast].prep()()

        assert 0x40041F in cfg.model.jump_tables
        assert cfg.model.jump_tables[0x40041F].jumptable_entries == [
            0x400755,
            0x40073D,
            0x40074D,
            0x400791,
            0x400789,
            0x40077B,
            0x40075F,
            0x40079F,
            0x4007AB,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400755,
            0x40074D,
            0x400791,
            0x400789,
            0x40077B,
            0x4007C1,
            0x4007B5,
            0x4007ED,
            0x4007E3,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x40079F,
            0x400401,
            0x400401,
            0x400401,
            0x40075F,
            0x400401,
            0x400401,
            0x400401,
            0x4007D7,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400725,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400821,
            0x4007F9,
            0x400401,
            0x400401,
            0x40082D,
            0x400717,
            0x400717,
            0x400717,
            0x400717,
            0x400717,
            0x400717,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400401,
            0x400725,
            0x40073D,
        ]

    def test_external_default_node(self):
        p = angr.Project(os.path.join(test_location, "x86_64", "switch_default_abort.o"), auto_load_libs=False)
        cfg = p.analyses.CFGFast()
        jt = cfg.model.jump_tables[0x40000D]
        assert jt.jumptable_entries is not None
        assert set(jt.jumptable_entries) == {
            0x400020,
            0x400030,
            0x400040,
            0x400050,
            0x400060,
        }

    def test_secondary_jumptable_amd64(self):
        proj = angr.Project(
            os.path.join(
                test_location, "x86_64", "windows", "9c75d43ec531c76caa65de86dcac0269d6727ba4ec74fe1cac1fda0e176fd2ab"
            ),
            auto_load_libs=False,
        )
        cfg = proj.analyses.CFGFast()
        jt = cfg.model.jump_tables[0x140051BBB]
        assert jt.jumptable is True
        assert len(jt.jumptables) == 2
        assert jt.jumptable_addr == 0x140051CA0  # we assume the indirect table is the primary jump table
        assert jt.jumptable_size == 0x140051CD6 - 0x140051CA0
        assert jt.jumptable_entry_size == 1
        assert jt.jumptables[0].addr == 0x140051CA0
        assert jt.jumptables[1].addr == 0x140051C84
        assert jt.jumptables[1].entry_size == 4
        assert jt.jumptables[1].size == 28
        assert jt.jumptables[1].entries == [
            0x51C3E,
            0x51C56,
            0x51BDE,
            0x51BF6,
            0x51C0E,
            0x51C26,
            0x51C6E,
        ]


class TestJumpTableResolverCallTables(unittest.TestCase):
    """
    Call table tests for JumpTableResolver
    """

    @staticmethod
    def _make_call_graph_edge_set_by_name(proj: angr.Project, src: str, dsts: set[str]):
        """
        Create set of edges {src->dsts : for d in dsts} by name
        """
        return {(proj.kb.labels.lookup(src), proj.kb.labels.lookup(dst), 0) for dst in dsts}

    def _run_calltable_test(self, binary: str, src: str, dsts: set[str]):
        """
        Compile `c_code`, load the binary in a project, check JumpTableResolver can properly recover jump targets
        """
        proj = angr.Project(binary, auto_load_libs=False)

        # Run initial CFG, without attempting indirect jump resolve
        cfg = proj.analyses.CFGFast(resolve_indirect_jumps=False)

        # Check that CFG analysis was unable to resolve these jumps
        expected_edges = self._make_call_graph_edge_set_by_name(proj, src, dsts)
        assert len(expected_edges.intersection(set(cfg.functions.callgraph.edges))) == 0

        func = proj.kb.functions[src]
        if l.level == logging.DEBUG:
            l.debug("Function Disassembly:\n%s", proj.analyses.Disassembly(func).render())

        # Verify exactly 1 block with an indirect Ijk_[Call|Boring] jumpkind
        blocks = [
            b
            for b in func.blocks
            if b.vex.jumpkind in ("Ijk_Call", "Ijk_Boring") and not isinstance(b.vex.next, pyvex.expr.Const)
        ]
        assert len(blocks) == 1, f"Expected 1 block with indirect Ijk_[Call|Boring] jumpkind, got {len(blocks)}"

        block = blocks[0]
        irsb = block.vex
        jtr = JumpTableResolver(proj)

        # Verify JumpTableResolver accepts this job
        assert jtr.filter(cfg, block.addr, func.addr, block, irsb.jumpkind), "JumpTableResolver denied solving"

        # Verify JumpTableResolver is correctly resolving table
        r, t = jtr.resolve(cfg, block.addr, func.addr, block, irsb.jumpkind)
        assert r, "JumpTableResolver failed"
        l.debug(
            "JumpTableResolver returned %d targets: %s",
            len(t),
            ", ".join([hex(n) for n in t]),
        )
        assert set(t) == {proj.kb.labels.lookup(d) for d in dsts}

        # Check that CFG analysis is able to correctly resolve the indirect jumps with JumpTableResolver
        cfg = proj.analyses.CFGFast(indirect_jump_resolvers=[jtr])
        expected_edges = self._make_call_graph_edge_set_by_name(proj, src, dsts)
        assert expected_edges.issubset(set(cfg.functions.callgraph.edges))

    def _run_common_test_matrix(self, name: str):
        # XXX: On x86 with PIE, call get_pc_thunk() is used to calculate table address. Can't handle it yet.
        for arch in ["x86_64", "x86"]:
            for opt_level in range(3):
                with self.subTest(name=name, arch=arch, opt_level=opt_level):
                    bin_path = os.path.join(test_location, arch, "calltable", f"{name}-o{opt_level}")
                    self._run_calltable_test(bin_path, "src_func", {f"dst_func_{i}" for i in range(4)})

    # Force compiler emitting calls for all optimization levels via return value mutation

    def test_calltable_resolver_without_check(self):
        self._run_common_test_matrix("resolver_without_check")

    def test_calltable_resolver_with_check(self):
        self._run_common_test_matrix("resolver_with_check")

    # Expect tail-call optimization to the jump target for the following tests on higher optimization levels

    def test_calltable_resolver_without_check_tailcall(self):
        self._run_common_test_matrix("resolver_without_check_tailcall")

    def test_calltable_resolver_with_check_tailcall(self):
        self._run_common_test_matrix("resolver_with_check_tailcall")


if __name__ == "__main__":
    unittest.main()
